﻿using System;
using System.Collections;
using System.Configuration;
using System.Collections.Generic;

namespace DevOnServer
{
    public class CGameServer
    {
        public bool init(CNetwork network, CDatabase database)
        {
            Database = database;

            Hashtable section = (Hashtable)ConfigurationManager.GetSection("Channel");
            m_acceptor = network.createAcceptor(Convert.ToInt32(section["port"]));
  
            if (m_acceptor == null)
            {
                CConsole.WriteLine("GameServer port {0} can't be used !", section["port"]);
                return false;
            }

            m_packetHandler = new CPacketHandler(this);
            ChatHandler = new CChatHandler(this);

            DataManager = new CDataManager();
            if (!DataManager.load())
                return false;

            if (!_createWorlds())
                return false;

            m_randgaSystem = new CRandgaManager(this);

            DataManager.endLoading();

            return true;
        }

        private bool _createWorlds()
        {
            CFileReader file = new CFileReader();

            if (!file.load("Data/Worlds.inc"))
            {
                Console.WriteLine("Can't open world script file 'Data/Worlds.inc'");
                return false;
            }

            Worlds = new Dictionary<int, CWorld>();

            string tok, name;
            int id, fieldSize;
            CWorld world;

            while (!file.end)
            {
                id = DataManager.getDefinedId(file.getString());

                if (id == -1)
                    continue;

                world = null;
                name = null;
                fieldSize = 128;

                tok = file.getString();
                while(tok != "}")
                {
                    switch (tok)
                    {
                        case "Name":
                            name = file.getString();
                            break;

                        case "FieldSize":
                            fieldSize = file.getInt();
                            break;
                    }

                    tok = file.getString();
                }

                if (name == null)
                    continue;

                world = new CWorld(this, id, name, fieldSize);

                if (world.init())
                {
                    CConsole.WriteLine("{0} : {1} Objects", name, world.ObjectCount);
                    Worlds[id] = world;
                }
            }

            return true;
        }

        public bool run()
        {
            while (m_acceptor.NewClients.Count > 0)
            {
                CGamePlayer player = _createPlayer(m_acceptor.NewClients.Dequeue());
                player.Client.send(CPacketCreator.greeting(player.ID));
            }

            for (int i = m_players.Count - 1; i >= 0; i--)
            {
                if (!m_players[i].Client.Connected)
                {
                    removePlayer(m_players[i]);
                }
                else if (m_players[i].Client.Incomming.Lenght > 0)
                {
                    while (m_packetHandler.handle(m_players[i])) ;

                    m_players[i].Client.Incomming.clear();
                }
            }

            CTimed.updateTime();

            foreach (int id in Worlds.Keys)
            {
                Worlds[id].update();
            }

            m_randgaSystem.update();

            return true;
        }

        public void removePlayer(CGamePlayer player)
        {
            if(player.Character != null)
            {
                if (player.Object != null)
                {
                    if (player.Object.World != null)
                    {
                        player.Object.World.removeObject(player.Object);
                    }

                    player.Object.updateCharacter();

                    Database.saveInventory(player.Object.Inventory);
                }

                Database.saveCharacter(player.Character);
            }

            player.Client.Free = true;
            m_players.Remove(player);
        }

        private CGamePlayer _createPlayer(CNetClient client)
        {
            CGamePlayer player = new CGamePlayer();

            m_nextPlayerId++;

            player.ID = m_nextPlayerId;
            player.Client = client;

            m_players.Add(player);
            return player;
        }

        private int m_nextPlayerId;

        private List<CGamePlayer> m_players = new List<CGamePlayer>();

        private CPacketHandler m_packetHandler;

        private CNetAcceptor m_acceptor;

        private CRandgaManager m_randgaSystem;

        public CDatabase Database { get; private set; }

        public CDataManager DataManager { get; private set; }

        public Dictionary<int, CWorld> Worlds { get; private set; }

        public CChatHandler ChatHandler { get; private set; }
    }
}